package ca.cbc.panacea.elixir.util;

import ca.cbc.panacea.elixir.entity.PanaceaInstance;
import ca.cbc.panacea.elixir.exception.ElixirException;
import com.google.common.base.Strings;
import com.google.common.io.CharStreams;
import com.google.common.io.Files;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.faces.application.FacesMessage;
import java.io.*;

import java.nio.charset.Charset;

/**
 * @author : Arash Bizhanzadeh <arash.bizhanzadeh@cbc.ca>
 *         Date: 11-11-25
 *         Time: 11:42 AM
 *         CBC.ca All rights reserved.
 */
public class PanaceaDaemon {
    private static Logger logger = LoggerFactory.getLogger(PanaceaDaemon.class);

    private static String START_COMMAND="/usr/sbin/jsvc -user webmaster -home /etc/alternatives/java_sdk/  -Xmx512m -jvm server " +
            "-errfile %s -outfile %s -pidfile %s -cp %s:/cbc/content/sites/cbc.ca/batchapps/elixir/panacea/panacea.jar ca.cbc.panacea.daemon.PanaceaDaemon";
            //Error file full path no extension, pid file full path no  extension, panacea instance root dir ( dir attribute).
    private  static String PROB_COMMAND="pgrep -f jsvc.*%s";//First argument is the instance dir;
    private static String STOP_COMMAND = "/usr/sbin/jsvc -stop -user webmaster -home /etc/alternatives/java_sdk/ " +
            "-errfile %s -outfile %s -pidfile %s  -cp %s:/cbc/content/sites/cbc.ca/batchapps/elixir/panacea/panacea.jar ca.cbc.panacea.daemon.PanaceaDaemon";

    public static String start(PanaceaInstance instance ) throws ElixirException {
        try {

            String procString = String.format(START_COMMAND, instance.getDaemonErrorlog(), instance.getDaemonOutputlog(),
                    instance.getDaemonPidFile(), ElixirProperties.instance.getDirectoryFor(instance)+"properties");
            logger.debug("Executing {}", procString);
            Process process = Runtime.getRuntime().exec(procString);
            process.getOutputStream().write('\n');
            int exit = process.waitFor();
            logger.debug("Process exit with code {}", exit);
            String processId;
            if ( exit == 0){
                Thread.currentThread().sleep(500);
                processId = probe(instance);
                 if(Strings.isNullOrEmpty(processId)){
                    logger.error("Failed to start process {}",instance.getDirectory());
                     throw new ElixirException("Failed to start Process");
                }else{
                     File pidFile = new File(instance.getDaemonPidFile());
                     if(!pidFile.exists()){
                         throw new ElixirException("Could not find the pid file, contact admin");
                     } else {
                         String pid = Files.readFirstLine(pidFile, Charset.forName("UTF-8"));
                         if (processId.lastIndexOf(pid)!= -1){
                             return pid;
                         } else{
                             throw new ElixirException(String.format("Pid file ( %s) doesn't contain the right pid (%s) , contact admin",pid,processId));
                         }
                     }
                 }
            } else {

                InputStream is = process.getErrorStream();

                String content = CharStreams.toString(new InputStreamReader(is, Charset.forName("UTF-8")));

                is.close();

                throw new ElixirException(content);

            }
        } catch (IOException e) {
            logger.error("IO Exception while starting Panacea instance " + instance.getDirectory(), e);
            throw new ElixirException("Command Not Found!");
        } catch (InterruptedException e) {
            logger.error("Interruption Exception while starting Panacea instance" + instance.getDirectory(),e);
            throw new ElixirException("Process Interrupted");
        }
    }
    public static boolean stop(PanaceaInstance instance) throws ElixirException {
        try{
            String procString = String.format(STOP_COMMAND, instance.getDaemonErrorlog(), instance.getDaemonOutputlog(),
                    instance.getDaemonPidFile(), ElixirProperties.instance.getDirectoryFor(instance)+"properties");
             logger.debug("Executing {}", procString);
             Process process = Runtime.getRuntime().exec(procString);

             InputStream istream = null,errStream = null;
             try {
                 istream = process.getInputStream();
                 logger.debug(CharStreams.toString(new InputStreamReader(istream)));
                 errStream = process.getErrorStream();
                 logger.debug(CharStreams.toString(new InputStreamReader(errStream)));
             } catch (IOException e) {
                 logger.error("Error reading process out stream", e);
                 throw new ElixirException("Could not communicate with Panacea Process, call admin!");
             } finally {
                 if (istream != null) {
                     istream.close();
                 }
                 if (errStream != null) {
                     errStream.close();
                 }
             }
            String processId = probe(instance);
            if(Strings.isNullOrEmpty(processId)){
                return true;
            } else {
                throw new ElixirException("Processed Could not be stopped, call Admin!");
            }
        } catch (IOException e) {
            logger.error("Error running stop command ", e);
            throw new ElixirException("Error stopping process "+ instance.getDirectory());
        }
    }
    public static String probe(PanaceaInstance instance) throws ElixirException {
        InputStream is = null;
        try {
            logger.debug("Probing {}", String.format(PROB_COMMAND, instance.getDaemonPidFile()));
            Process process = Runtime.getRuntime().exec(String.format(PROB_COMMAND,instance.getDaemonPidFile()));
            is = process.getInputStream();
            String content = CharStreams.toString(new InputStreamReader(is));
            logger.debug("output content from process is {}", content);

            return content.replace('\n', ' ');

        } catch (IOException e) {
            logger.error("Error in probing the instance " + instance.getDirectory(), e);
            throw new ElixirException("Could not probe instance " + instance.getDirectory());
        }finally{
            if(is != null){
                try {
                    is.close();
                } catch (IOException e) {
                    logger.error("Error closing output stream", e);
                }
            }
        }
    }
}
